#include "MutaCurve.h"
#include "qwt/qwt_curve_fitter.h"

MutaCurve::MutaCurve(QString ObjectID,QString owner,QPointF p1,QPointF p2,int layer) :
    MutaObject(ObjectID,Muta::Curve,owner),
    QGraphicsPathItem(),
    layer(layer),
    time(0),
    boxColor(155,255,255,10),
    curveProgress(0)
{
    setPos(p1);
    setFlag( QGraphicsItem::ItemIsSelectable, true );
    setFlag( QGraphicsItem::ItemIsMovable, true );
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    addControlPoint(p1);
    //controlPoints.first()->setFlag( QGraphicsItem::ItemIsSelectable, false );
    //controlPoints.first()->setFlag( QGraphicsItem::ItemIsMovable, false );
    addControlPoint(p2+this->pos());

    boxBrush.setColor(boxColor);
    boxBrush.setStyle(Qt::SolidPattern);
    boxPen.setWidth(1);
    boxPen.setColor(boxColor);
}

MutaCurve::MutaCurve(QString ObjectID,QString owner,QPointF p1,QPointF p2,int layer, int zero) :
    MutaObject(ObjectID,Muta::Curve,owner),
    QGraphicsPathItem(),
    layer(layer),
    time(0),
    boxColor(155,255,255,10),
    curveProgress(0)
{
    setPos(p1);
    setFlag( QGraphicsItem::ItemIsSelectable, true );
    setFlag( QGraphicsItem::ItemIsMovable, true );
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    addControlPointNQ(p1);

    boxBrush.setColor(boxColor);
    boxBrush.setStyle(Qt::SolidPattern);
    boxPen.setWidth(1);
    boxPen.setColor(boxColor);
}

void MutaCurve::buildPath()
{
    QPainterPath path;
    /*
    path.moveTo(controlPoints.at(0)->pos());
    for(int i=1;i<controlPoints.size()-1;i+=2) {

        path.cubicTo(
            controlPoints.at(i)->pos() - ((controlPoints.at(i)->pos() - controlPoints.at(i-1)->pos())*0.5),
            controlPoints.at(i+1)->pos() - ((controlPoints.at(i+1)->pos() - controlPoints.at(i)->pos())*0.5),
            controlPoints.at(i+1)->pos()
        );
    }
    */
    QPolygonF polygon;
    //polygon.fromList(controlPoints);
    for(int i=0;i<controlPoints.size();i++) {
        polygon.append(controlPoints.at(i)->pos());
    }

    QwtSplineCurveFitter curveFitter;
    polygon = curveFitter.fitCurve(polygon);
    curvePoly = polygon;
    path.addPolygon(polygon);
    setPath(path);
}

int MutaCurve::type() const
{
    return mutaType;
}

void MutaCurve::addControlPoint(QPointF point) {
    controlPoints.append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5),controlPoints.size(),-5,-5,10,10,this));
    QObject::connect(controlPoints.at(controlPoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));

    buildPath();
    setColor();
    buildControlPointString();
}

void MutaCurve::addControlPointNQ(QPointF point) {
    controlPoints.append(new ControlPoint(point-this->pos(),controlPoints.size(),-5,-5,10,10,this));
    QObject::connect(controlPoints.at(controlPoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));

    buildPath();
    setColor();
    buildControlPointString();
}

void MutaCurve::cPointMoved(QPointF pos,int num)
{
    controlPoints.at(num)->setPos(Muta::quantizePoint(pos,Muta::BEAT_PIXELS,15));
    if(num!=0) {
    //    QPointF curvePoint = (controlPoints.at(num)->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + controlPoints.at(controlPoints.size()-2)->pos();
    //    curvePoints.at(num-1)->setPos(curvePoint);
    } else {
        //QPointF curvePoint = (controlPoints.at(1)->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + (controlPoints.at(controlPoints.size()-2)->pos());
        //curvePoints.at(0)->setPos(curvePoint);
        //setPos(pos);
    }
    buildPath();
    setColor();
    buildControlPointString();
}

void MutaCurve::setPos(const QPointF &pos)
{
    QGraphicsPathItem::setPos(Muta::quantizePoint(pos,Muta::BEAT_PIXELS,15)+QPointF(0,7.5));
    emit posChanged(objectID,pos);
}


void MutaCurve::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
    QGraphicsPathItem::mouseMoveEvent(event);
    setPos(this->pos());
}

void MutaCurve::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QGraphicsPathItem::paint(painter,option,widget);
}

void MutaCurve::setFinalPoint(QPointF p)
{
    controlPoints.last()->setPos(Muta::quantizePoint(p,Muta::BEAT_PIXELS,15) - this->pos()+QPointF(0,7.5));
    QPointF curvePoint = (controlPoints.last()->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + controlPoints.at(controlPoints.size()-2)->pos();
    buildPath();
    setColor();
    buildControlPointString();
}

void MutaCurve::setColor()
{
    QColor fillColor;
    QColor firstCPointColor;
    QColor curvePColor;
    switch(layer) {
        case 0:
            fillColor = QColor(227,244,247,255);
            firstCPointColor = QColor(140,204,240,255);
            curvePColor = QColor(64,187,236,255);
            break;
        case 1:
            fillColor = QColor(216,191,215,255);
            firstCPointColor = QColor(194,118,177,255);
            curvePColor = QColor(124,40,125,255);
            break;
        case 2:
            fillColor = QColor(255,153,153);
            firstCPointColor = QColor(242, 99, 75,255);
            curvePColor = QColor(237, 31,36,255);
            break;
        case 3:
            fillColor = QColor(238,232,169,255);
            firstCPointColor = QColor(179,210,53,255);
            curvePColor = QColor(86,107,48,255);
            break;
        case 4:
            fillColor = QColor(	255,204,153,255);
            firstCPointColor = QColor(210,106,40,255);
            curvePColor = QColor(139,70,31,255);
            break;
    }

    QLinearGradient gradient(0, 0, 0, 255);
    gradient.setColorAt(0.0, QColor(200,200,220,255));
    gradient.setColorAt(0.1, QColor(80,80,80,255));
    gradient.setColorAt(0.6, fillColor);
    gradient.setColorAt(0.975, QColor(30,30,30,255));
    gradient.setColorAt(1.0, QColor(50,50,50,255));
    gradient.setInterpolationMode(QGradient::ColorInterpolation);

    QBrush brush;
    brush.setColor(fillColor);
    brush.setStyle(Qt::SolidPattern);



    QPen pen;
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setCapStyle(Qt::RoundCap);
    pen.setBrush(brush);
    pen.setWidth(6);
    pen.setColor(fillColor);
    setPen(pen);
    pen.setWidth(1);

    for(int i=1;i<controlPoints.size();i++) {
        controlPoints.at(i)->setPen(pen);
        controlPoints.at(i)->setBrush(brush);
    }

    brush.setColor(firstCPointColor);
    pen.setBrush(brush);
    pen.setWidth(1);
    pen.setColor(firstCPointColor);
    controlPoints.at(0)->setPen(pen);
    controlPoints.at(0)->setBrush(brush);

    brush.setColor(curvePColor);
    pen.setBrush(brush);
    pen.setWidth(3);
    pen.setColor(QColor(0,0,0,255));
    pen.setColor(curvePColor);
    /*
    for(int i=0;i<curvePoints.size();i++) {
        curvePoints.at(i)->setPen(pen);
        curvePoints.at(i)->setBrush(brush);
    }
    */
}

QStringList MutaCurve::getProperties()
{
    QStringList properties;
    properties << "mc" << owner << QString::number(x()) << QString::number(y()) << QString::number(layer);
    for(int i=0;i<controlPoints.size();i++) {
        properties << QString::number(controlPoints.at(i)->x()) << QString::number(controlPoints.at(i)->y());
    }

    return properties;
}

int MutaCurve::getLayer()
{
    return layer;
}

QVariant MutaCurve::itemChange(GraphicsItemChange change, const QVariant &value) {
    QVariant variant = QGraphicsPathItem::itemChange(change, value);

    if(change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged)
    {
        variant.setValue(Muta::quantizePoint(variant.toPointF(),Muta::BEAT_PIXELS,15)+QPointF(0,7.5));
    }

    return variant;
}

void MutaCurve::forceOSCthulhuUpdate()
{
    emit posChanged(objectID, pos());
}

void MutaCurve::buildControlPointString()
{
    controlPointString.clear();
    for(int i=0;i<controlPoints.size();i++) {
        controlPointString.append(QString().number((int)(controlPoints.at(i)->pos().x())));
        controlPointString.append(",");
        controlPointString.append(QString().number((int)(controlPoints.at(i)->pos().y())));
        if(i!=controlPoints.size()-1) {
            controlPointString.append(",");
        }
    }
    emit controlPointAdded(objectID,controlPointString);
}

void MutaCurve::setControlPoints(QString aCPS)
{
    if(this->controlPointString.compare(aCPS) != 0) {
        controlPointString = aCPS;
        QList<QPointF> tempControlPoints;
        //QList<QPointF> tempCurvePoints;
        //QStringList controlAndCurves = aCPS.split("&",QString::SkipEmptyParts);
        QStringList tempControlString = aCPS.split(",",QString::SkipEmptyParts);

        for(int i=0;i<tempControlString.size();i+=2) {
            tempControlPoints.append(
                QPointF(tempControlString.at(i).toInt(),tempControlString.at(i+1).toInt())
            );
        }

        for(int i=1;i<controlPoints.size();i++) {
            controlPoints.at(i)->setPos(tempControlPoints.at(i));
        }
        if(tempControlPoints.size()!=(controlPoints.size())) {
            for(int i=controlPoints.size();i<=tempControlPoints.size() -1;i++) {
                QPointF point = tempControlPoints.at(i);
                controlPoints.append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15),controlPoints.size(),-5,-5,10,10,this));
                QObject::connect(controlPoints.at(controlPoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
            }
        }

        buildPath();
        setColor();
    }
}

QPolygonF MutaCurve::getCurvePoly()
{
    return curvePoly;
}

int MutaCurve::getCurveProgress()
{
    return curveProgress;
}

void MutaCurve::setCurveProgress(int curveProgress)
{
    this->curveProgress = curveProgress;
}
